k-图着色
Get the knowledge flowing and circulating! :)
目录
标题:图的着色问题概念相关问题相关术语通俗说法代码代码 -
无向图
图着色问题(Graph Coloring Problem,GCP),又称着色问题,是最著名的NP-完全问题之一。
给定一个无向图
道路着色问题(Road Coloring Problem)是图论中最著名的猜想之一。
参考:维基百科
图的
图的
图色数(英语:chromatic number),也被称为顶点色数(vertex chromatic number):指将一张图上的每个顶点染色,使得相邻的两个点颜色不同,最小需要的颜色数。最小染色数用
边色数(edge chromatic number):指将一张图上的每条边染色,使有公共顶点的边颜色不同,最少需要的颜色数叫边色数,用
问题1
-着色判定问题 给定一个图
,给定一个 种颜色,有没有一个方案能够让图 中的任意相邻顶点的颜色不一样?
有没有?(True or False)
原图 方案1 问题2
-着色判定问题拓展 给定一个图
,给定一个 种颜色,有多少方案能够让图 中的任意相邻顶点的颜色不一样?
有多少?(How many)
从这个拓展问题可知,
-着色的答案不唯一。
原图 方案1 方案2
问题3 m-着色优化问题
给定一个图
,若该图至少需要 种颜色才能够让图 中的任意相邻顶点的颜色不一样,问这个 是多少?
是多少?
问题1
xxxxxxxxxx75123using namespace std;4
5const int maxn = 105;6
7int G[maxn][maxn];8int color[maxn];9
10// ans 表示是否存在方案[0:不存在;1:存在]。 11bool ans; // ans如果是1,则表示对于图G,可以用m种颜色着色,使G中每条边的2个顶点着不同颜色。 12
13// n:顶点数14// m:颜色数15// k:边数 16int n, m, k;17
18void init()19{20 ans = 0; // 初始时,表示不存在这样的方案。 21 memset(G, 0, sizeof G);22 memset(color, 0 , sizeof color);23}24
25void dfs(int cur)26{27 if(cur > n)28 {29 ans = 1;30 return;31 }32 for(int i = 1; i <= m; i++) // 对cur结点尝试使用每一种颜色进行涂色33 {34 bool flag = 1;35 // cur之前的结点必被涂色36 for(int j = 1; j < cur; j++)37 {38 if(G[j][cur] == 1 && color[j] == i)39 {40 flag = 0; // 只要有一个冲突都不行41 break;42 }43 }44 // 如果可以涂上i颜色,则考虑下一个结点的情况45 if(flag)46 {47 color[cur] = i; // 涂上颜色48 dfs(cur + 1);49 }50 else // 如果到这一步第cur个结点无法着色,则返回探寻其他方案51 {52 color[cur] = 0; // 擦除颜色(回溯);53 }54 }55
56}57
58
59int main()60{61 // 可以一个窗口输入多组数据 62 while(cin>>n>>k>>m)63 {64 init();65 for(int i = 1; i <= k; i++)66 {67 int s, e;68 cin>>s>>e;69 G[s][e] = G[e][s] = 1; // 无向图(对称) 70 }71 dfs(1);72 cout<<ans<<endl; // 输出 0 | 1 73 }74 return 0;75}
问题2
xxxxxxxxxx107123using namespace std;4
5const int maxn = 105;6
7int G[maxn][maxn];8int color[maxn];9
10
11// 图着色判断问题(拓展) 12// ans 表示存在多少种方案13int ans;14
15// n:顶点数16// m:颜色数17// k:边数 18int n, m, k;19
20void init()21{22 ans = 0; // 初始时默认为没有方案。 23 memset(G, 0, sizeof G);24 memset(color, 0 , sizeof color);25}26
27void dfs(int cur)28{29 if(cur > n)30 {31 ans = ans + 1; // 找到1种,就加1 32 return;33 }34 for(int i = 1; i <= m; i++) // 对cur结点尝试使用每一种颜色进行涂色35 {36 bool flag = 1;37 // cur之前的结点必被涂色38 for(int j = 1; j < cur; j++)39 {40 if(G[j][cur] == 1 && color[j] == i)41 {42 flag = 0; // 只要有一个冲突都不行43 break;44 }45 }46 // 如果可以涂上i颜色,则考虑下一个结点的情况47 if(flag)48 {49 color[cur] = i; // 涂上颜色50 dfs(cur + 1);51 color[cur] = 0; // 擦除颜色(回溯)52 }53 }54
55}56
57void dfs2(int cur)58{59 if(cur > n)60 {61 ans = ans + 1; // 找到1种,就加1 62 return;63 }64 for(int i = 1; i <= m; i++) // 对cur结点尝试使用每一种颜色进行涂色65 {66 color[cur] = i; // 涂上颜色(先涂了再说)67 68 int flag = 1;69 // cur和其他节点的涂色情况检查70 for(int j = 1; j <= n; j++)71 {72 if(G[j][cur] == 1 && color[j] == i)73 {74 flag = 0; // 只要有一个冲突都不行75 break;76 }77 }78 // 如果可以涂上i颜色,则考虑下一个结点的情况79 80 // 如果检查通过,则flag还是1(没有进入上面for循环里的if语句)81 // 如果检查没通过,则flag肯定是0了(下面这句if就不执行了)82 if(flag) 83 {84 dfs2(cur + 1);85 }86 87 color[cur] = 0; // 擦除颜色(回溯)88 }89}90
91int main()92{93 // 可以一个窗口输入多组数据 94 while(cin>>n>>k>>m)95 {96 init();97 for(int i = 1; i <= k; i++)98 {99 int s, e;100 cin>>s>>e;101 G[s][e] = G[e][s] = 1; // 无向图(对称) 102 }103 dfs(1); //dfs2(1),测试第2种代码(思路更清晰)104 cout<<ans<<endl; // 输出总方案数 105 }106 return 0;107}

5个顶点:编号从1~5
7条边
3种颜色:红、绿、蓝
注意:顶点编号从1开始,不是从0开始。
输出:6
xxxxxxxxxx815 7 321 232 343 454 565 171 381 4
13个顶点:编号从1~13
41条边
3种颜色:红、绿、蓝
注意:顶点编号从1开始,不是从0开始。
输出:336
xxxxxxxxxx42113 41 321 331 541 651 1062 572 682 793 1103 4113 5123 13134 7144 8155 1165 2175 3185 6195 9206 1216 2226 5236 12246 13257 2267 4277 11288 4298 11309 5319 103210 13310 93410 113510 133611 73711 83811 103912 64013 34113 64213 10
xxxxxxxxxx815 7 321 331 442 352 563 473 584 5

针对
void dfs(int cur)和 测试样例2的过程示意图(输出1种着色方案)



条件:元素=[1,2,3,4,5,6,7,8,9],互斥=[(1,4),(2,5),(1,5),(5,6),(7,8),(3,9),(2,8),(4,5)]
要求:把元素组成
个组, 保证互斥元素不在同一个组里, 并且 最小。 思路:这个问题实际上就是图的
-可着色优化问题。
https://blog.csdn.net/qq_17550379/article/details/102563756
https://blog.csdn.net/Wu_L7/article/details/125062506
https://oi-wiki.org/graph/color/
https://baike.baidu.com/item/%E5%9B%BE%E7%9D%80%E8%89%B2%E9%97%AE%E9%A2%98/8928655